<template>
	<div id="app">
		<div class="container">
			<!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的，并设置ref让vue获取到element -->
			<div class="bpmn-canvas" ref="canvas"></div>
			<!-- 工具栏显示的地方 -->
			<div class="bpmn-js-properties-panel" id="js-properties-panel">
				<div v-show="nodeStatus" class="rightMenu">
					<el-form ref="form" :model="form" label-width="100px">
						<el-form-item label="节点名称">
							<el-input
								v-model="form.name"
								palceholder="请输入节点名称"
								@change="
									event => changeField(event, 'name')
								"></el-input>
						</el-form-item>
						<el-form-item label="选择表单">
							<el-select
								v-model="form.region"
								placeholder="请选择表单">
								<el-option
									label="区域一"
									value="shanghai"></el-option>
								<el-option
									label="区域二"
									value="beijing"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item label="节点版本">
							<el-input
								v-model="form.bide"
								palceholder="请输入节点版本"></el-input>
						</el-form-item>
						<el-form-item label="节点权限">
							<el-button type="primary" size="small">
								查看/设置
							</el-button>
						</el-form-item>
						<el-form-item label="审批设置">
							<el-checkbox-group v-model="form.type">
								<el-checkbox
									label="转交"
									name="type"></el-checkbox>
								<el-checkbox
									label="加签"
									name="type1"></el-checkbox>
								<el-checkbox
									label="驳回"
									name="type2"></el-checkbox>
								<el-checkbox
									label="待定"
									name="type3"></el-checkbox>
								<el-checkbox
									label="拒绝"
									name="type4"></el-checkbox>
								<el-checkbox
									label="建议拒绝"
									name="type5"></el-checkbox>
							</el-checkbox-group>
						</el-form-item>
						<el-form-item label="驳回节点">
							<el-select
								v-model="form.region"
								placeholder="请选择驳回节点">
								<el-option
									label="区域一"
									value="shanghai"></el-option>
								<el-option
									label="区域二"
									value="beijing"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item label="是否抄送">
							<el-radio-group v-model="form.resource">
								<el-radio label="是"></el-radio>
								<el-radio label="否"></el-radio>
							</el-radio-group>
						</el-form-item>
						<el-form-item label="抄送用户">
							<el-select
								v-model="form.region"
								multiple
								placeholder="请选择抄送用户">
								<el-option
									label="区域一"
									value="shanghai"></el-option>
								<el-option
									label="区域二"
									value="beijing"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item multiple label="审批角色">
							<el-select
								v-model="form.regionw"
								placeholder="请选择审批角色">
								<el-option
									label="区域一"
									value="shanghai"></el-option>
								<el-option
									label="区域二"
									value="beijing"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item label="指定审批人员">
							<el-radio-group v-model="form.resource3">
								<el-radio label="是"></el-radio>
								<el-radio label="否"></el-radio>
							</el-radio-group>
						</el-form-item>
						<el-form-item label="审批用户">
							<el-select
								v-model="form.region"
								multiple
								placeholder="请选择审批用户">
								<el-option
									label="区域一"
									value="shanghai"></el-option>
								<el-option
									label="区域二"
									value="beijing"></el-option>
							</el-select>
						</el-form-item>
						<el-form-item label="可拒绝用户">
							<el-select
								v-model="form.regionw"
								multiple
								placeholder="请选择可拒绝用户">
								<el-option
									label="区域一"
									value="shanghai"></el-option>
								<el-option
									label="区域二"
									value="beijing"></el-option>
							</el-select>
						</el-form-item>
					</el-form>
				</div>
				<div v-show="conditionStatus">
					<div>
						<div style="margin: 10px 5px">
							<span>节点名称</span>
							<span>{{}}</span>
						</div>
						<div v-for="(val, index) in formData" :key="index">
							<el-card>
								<div>{{ val.title }}{{ index + 1 }}</div>
								<div
									v-for="(item, index) in val.data"
									:key="index">
									<div style="display: flex">
										<el-select
											v-model="item.type"
											placeholder="请选择"
											@change="
												e => firstChange(e, item, val)
											">
											<el-option
												v-for="res in typeOptions"
												:key="res.value"
												:label="res.label"
												:value="res.value"></el-option>
										</el-select>
										<el-select
											v-model="item.type"
											placeholder="请选择"
											v-if="item.state1"
											@change="
												e => secendChange(e, item, val)
											">
											<el-option
												v-for="res1 in typeOptions"
												:key="res1.value"
												:label="res1.label"
												:value="res1.value"></el-option>
										</el-select>
										<el-input
											v-model="item.input"
											placeholder="请输入内容"
											disabled
											v-if="!item.state1"></el-input>
										<el-select
											v-model="item.type"
											placeholder="请选择"
											v-if="item.state2"
											@change="
												e => seardChange(e, item, val)
											">
											<el-option
												v-for="res2 in typeOptions"
												:key="res2.value"
												:label="res2.label"
												:value="res2.value"></el-option>
										</el-select>
										<el-input
											v-model="item.inputValue"
											placeholder="请输入内容"
											disabled
											v-if="!item.state2"></el-input>
									</div>
									<div>
										<el-tag v-if="val.data.length > 1">
											or
										</el-tag>
									</div>
								</div>
								<div
									style="
										text-align: center;
										margin-top: 10px;
									">
									<el-button
										type="primary"
										icon="el-icon-plus"
										@click="addField(val)">
										增加字段
									</el-button>
								</div>
							</el-card>
							<el-tag type="warning" v-if="formData.length > 1">
								and
							</el-tag>
						</div>
						<div style="text-align: center; margin-top: 10px">
							<el-button
								type="primary"
								icon="el-icon-plus"
								@click="addCondition()">
								增加条件
							</el-button>
						</div>
					</div>
				</div>
			</div>

			<!-- 把操作按钮写在这里面 -->
			<div class="action">
				<el-tooltip effect="light" content="导入Bpmn" placement="top">
					<el-upload
						action
						class="upload-demo"
						:before-upload="openBpmn">
						<el-button icon="el-icon-folder-opened"></el-button>
					</el-upload>
				</el-tooltip>
				<el-tooltip effect="light" content="新建流程" placement="top">
					<el-button
						class="new"
						icon="el-icon-circle-plus"
						@click="newDiagram"></el-button>
				</el-tooltip>
				<el-tooltip effect="light" content="下载Bpmn" placement="top">
					<el-button
						icon="el-icon-download"
						@click="downloadBpmn"></el-button>
				</el-tooltip>
				<el-tooltip effect="light" content="下载Svg" placement="top">
					<el-button
						icon="el-icon-picture"
						@click="downloadSvg"></el-button>
				</el-tooltip>

				<el-button-group style="margin-left: 10px">
					<el-button @click="handlerUndo">撤销</el-button>
					<el-button @click="handlerRedo">恢复</el-button>
				</el-button-group>
				<el-button-group style="margin-left: 10px">
					<el-button @click="handlerZoom(0.1)">放大</el-button>
					<el-button @click="handlerZoom(-0.1)">缩小</el-button>
					<el-button @click="handlerZoom(0)">还原</el-button>
				</el-button-group>
				<!-- <el-button-group style="margin-left: 10px;">
                    <el-button @click="perviewXML">xml预览</el-button>
                    <el-button @click="perviewSVG">svg预览</el-button>
                </el-button-group> -->
				<el-button-group style="margin-left: 10px">
					<el-button @click="save()">保存</el-button>
				</el-button-group>

				<!-- 预览弹出 -->
				<el-dialog
					title="XML预览"
					append-to-body
					width="80%"
					:visible.sync="perviewXMLShow">
					<div style="max-height: 65vh; overflow: auto">
						<pre v-highlight="perviewXMLStr"><code></code></pre>
					</div>
				</el-dialog>
				<el-dialog
					title="SVG预览"
					append-to-body
					width="80%"
					:visible.sync="perviewSVGShow">
					<div style="text-align: center" v-html="perviewSVGData" />
				</el-dialog>

				<!-- <a hidden ref="downloadLink"></a> -->
			</div>
		</div>
	</div>
</template>

<script>
	// bpmn 相关依赖
	// import 'bpmn-js/dist/assets/diagram-js.css'
	// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'
	// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css'
	// import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'

	// 左边工具栏以及编辑节点的样式
	// import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css'

	// import BpmnModeler from "bpmn-js/lib/Modeler";
	// 左边工具栏以及节点
	// import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
	// 右边的工具栏
	// import propertiesPanelModule from "bpmn-js-properties-panel";
	// import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";

	// BPMN国际化
	// import customTranslate from './customTranslate/customTranslate';
	// 自定义汉化模块
	var customTranslateModule = {
		translate: ['value', customTranslate],
	};

	export default {
		name: 'Bpmn',
		props: {
			/* 编辑器的内容 */
			value: {
				type: String,
				default: '',
			},
			/* 只读 */
			readOnly: {
				type: Boolean,
				default: false,
			},
		},
		components: {},
		data() {
			return {
				form: {
					name: '',
					region: '',
					date1: '',
					date2: '',
					delivery: false,
					type: [],
					resource: '',
					desc: '',
				},
				nodeId: '',
				xmlData: '',
				nodeStatus: false,
				conditionStatus: false,
				element: {
					id: 1,
					name: '2',
				},
				eventTypesArr: [
					{ value: '1', label: 2 },
					{ value: '3', label: 4 },
				],
				eventType: '1',
				bpmnModeler: null,
				scale: 1,
				canvas: null,
				bpmnTemplate: `
            <?xml version="1.0" encoding="UTF-8"?>
            <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
            <process id="Process_1" isExecutable="false">
                <startEvent id="StartEvent_1y45yut" name="开始">
                <outgoing>SequenceFlow_0h21x7r</outgoing>
                </startEvent>
                <task id="Task_1hcentk">
                <incoming>SequenceFlow_0h21x7r</incoming>
                </task>
                <sequenceFlow id="SequenceFlow_0h21x7r" sourceRef="StartEvent_1y45yut" targetRef="Task_1hcentk" />
            </process>
            <bpmndi:BPMNDiagram id="BpmnDiagram_1">
                <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
                <bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent_1y45yut">
                    <omgdc:Bounds x="152" y="102" width="36" height="36" />
                    <bpmndi:BPMNLabel>
                    <omgdc:Bounds x="160" y="145" width="22" height="14" />
                    </bpmndi:BPMNLabel>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape id="Task_1hcentk_di" bpmnElement="Task_1hcentk">
                    <omgdc:Bounds x="240" y="80" width="100" height="80" />
                </bpmndi:BPMNShape>
                <bpmndi:BPMNEdge id="SequenceFlow_0h21x7r_di" bpmnElement="SequenceFlow_0h21x7r">
                    <omgdi:waypoint x="188" y="120" />
                    <omgdi:waypoint x="240" y="120" />
                </bpmndi:BPMNEdge>
                </bpmndi:BPMNPlane>
            </bpmndi:BPMNDiagram>
            </definitions>
        `,
				perviewXMLStr: null,
				perviewSVGData: null,
				perviewXMLShow: false,
				perviewSVGShow: false,
				formData: [
					{
						title: '条件',
						data: [
							{
								name: '条件',
								type: '',
								condition: '',
								value: '',
								input: '=',
								inputValue: '',
								state1: true,
								state2: true,
							},
						],
					},
				],
				typeOptions: [],
			};
		},
		mounted() {
			this.init();
		},
		methods: {
			// 条件节点-第一个下拉框
			firstChange(value, info, data) {},
			// 条件节点-第二个下拉框
			secendChange(value, info, data) {},
			// 条件节点-第三个下拉框
			seardChange(value, info, data) {},
			// 添加字段
			addField(info) {
				this.formData.map(res => {
					if (res.id == info.id) {
						let obj = {
							name: '条件',
							id: res.data.length + 1,
							type: '',
							condition: '',
							value: '',
							input: '=',
							inputValue: '',
							state1: true,
							state2: true,
						};
						res.data.push(obj);
					}
				});
				console.log(info, 2222222222);
			},
			// 添加条件
			addCondition() {
				let obj = {
					title: '条件',
					id: this.formData.length + 1,
					data: [
						{
							name: '条件',
							id: 1,
							type: '',
							condition: '',
							value: '',
							input: '=',
							inputValue: '',
							state1: true,
							state2: true,
						},
					],
				};
				this.formData.push(obj);
			},
			// 保存
			save() {
				console.log(this.xmlData);
			},
			changeField(e, info) {
				const modeling = this.bpmnModeler.get('modeling');
				if (JSON.stringify(this.nodeId) === '{}') {
					this.$message.info('请保证要更改的节点处于选中状态!');
					return false;
				} else {
					modeling.updateLabel(this.nodeId, e);
				}
				this.$set(this.element, 'name', e);
				this.name1 = e;
			},
			// 跟新节点名字
			updataNodeName() {
				const modeling = this.bpmnModeler.get('modeling');
				modeling.updateLabel(this.nodeId, this.name1);
			},
			changeEventType() {},
			newDiagram() {
				this.createNewDiagram(this.bpmnTemplate);
			},

			handlerRedo() {
				this.bpmnModeler.get('commandStack').redo();
			},
			handlerUndo() {
				this.bpmnModeler.get('commandStack').undo();
			},
			handlerZoom(radio) {
				const newScale = !radio ? 1.0 : this.scale + radio;
				this.bpmnModeler.get('canvas').zoom(newScale);
				this.scale = newScale;
			},

			async downloadBpmn() {
				try {
					const { xml } = await this.bpmnModeler.saveXML({
						format: true,
					});
					// 获取文件名
					const name = `${this.getFilename(xml)}.bpmn`;
					// 将文件名以及数据交给下载方法
					this.download({ name: name, data: xml });
				} catch (error) {
					this.toast.error('下载Bpmn失败，请重试');
				}
			},
			async downloadSvg() {
				try {
					const { xml } = await this.bpmnModeler.saveXML({
						format: true,
					});
					// 获取文件名
					const name = `${this.getFilename(xml)}.svg`;

					// 从建模器画布中提取svg图形标签
					let context = '';
					const djsGroupAll =
						this.$refs.canvas.querySelectorAll('.djs-group');
					for (let item of djsGroupAll) {
						context += item.innerHTML;
					}
					// 获取svg的基本数据，长宽高
					const viewport = this.$refs.canvas
						.querySelector('.viewport')
						.getBBox();

					// 将标签和数据拼接成一个完整正常的svg图形
					const svg = `
            <svg
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="${viewport.width}"
              height="${viewport.height}"
              viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
              version="1.1"
              >
              ${context}
            </svg>
          `;
					// 将文件名以及数据交给下载方法
					this.download({ name: name, data: svg });
				} catch (error) {
					this.toast.error('下载Svg失败，请重试');
				}
			},

			openBpmn(file) {
				const reader = new FileReader();
				// 读取File对象中的文本信息，编码格式为UTF-8
				reader.readAsText(file, 'utf-8');
				reader.onload = () => {
					//读取完毕后将文本信息导入到Bpmn建模器
					this.createNewDiagram(reader.result);
				};
				return false;
			},

			getFilename(xml) {
				let start = xml.indexOf('process');
				let filename = xml.substr(start, xml.indexOf('>'));
				filename = filename.substr(filename.indexOf('id') + 4);
				filename = filename.substr(0, filename.indexOf('"'));
				return filename;
			},

			download({ name = 'diagram.bpmn', data }) {
				// 这里就获取到了之前设置的隐藏链接
				const downloadLink = this.$refs.downloadLink;
				// 把输就转换为URI，下载要用到的
				const encodedData = encodeURIComponent(data);

				if (data) {
					// 将数据给到链接
					downloadLink.href =
						'data:application/bpmn20-xml;charset=UTF-8,' +
						encodedData;
					// 设置文件名
					downloadLink.download = name;
					// 触发点击事件开始下载
					downloadLink.click();
				}
			},
			// XML预览
			async perviewXML() {
				try {
					const { xml } = await this.bpmnModeler.saveXML({
						format: true,
					});
					this.perviewXMLStr = xml;
					this.perviewXMLShow = true;
				} catch (error) {
					this.toast.error('预览失败，请重试');
				}
			},
			// SVG预览
			async perviewSVG() {
				try {
					const { svg } = await this.bpmnModeler.saveSVG();
					this.perviewSVGData = svg;
					this.perviewSVGShow = true;
				} catch (error) {
					this.toast.error('预览失败，请重试');
				}
			},

			async init() {
				// 获取画布 element
				this.canvas = this.$refs.canvas;

				// 创建Bpmn对象
				this.bpmnModeler = new BpmnModeler({
					// 设置bpmn的绘图容器为上门获取的画布 element
					container: this.canvas,

					// 加入工具栏支持
					propertiesPanel: {
						parent: '#js-properties-panel',
					},

					additionalModules: [
						propertiesProviderModule,
						customTranslateModule,
					],
					moddleExtensions: {
						camunda: camundaModdleDescriptor,
					},
				});

				await this.createNewDiagram(
					this.value ? this.value : this.bpmnTemplate,
				);
				// 监听画布点击事件，存储变化值
				var that = this;
				this.$refs.canvas.addEventListener('click', async function () {
					try {
						const { xml } = await that.bpmnModeler.saveXML({
							format: true,
						});
						that.$emit('input', xml);
						that.xmlData = xml;
					} catch (error) {
						that.$modal.msgError('实时保存失败');
					}
				});
				this.addEventBusListener();
			},
			async createNewDiagram(bpmn) {
				// 将字符串转换成图显示出来;
				try {
					const result = await this.bpmnModeler.importXML(bpmn);
				} catch (err) {
					this.$modal.msgError(
						'打开模型出错,请确认该模型符合Bpmn2.0规范',
					);
				}
			},

			// 监听
			addEventBusListener() {
				// 监听 element
				let that = this;
				const eventBus = this.bpmnModeler.get('eventBus');
				const eventTypes = ['element.click', 'element.changed'];
				eventTypes.forEach(function (eventType) {
					eventBus.on(eventType, function (e) {
						console.log(e, 3333333);
						const { element } = e;

						if (!e || e.element.type == 'bpmn:Process') return;
						if (eventType === 'element.changed') {
							that.elementChanged(eventType, e);
						} else if (eventType === 'element.click') {
							console.log(e);
							that.nodeId = element;
							if (e.element.type == 'bpmn:Task') {
								that.nodeStatus = true;
								that.conditionStatus = false;
							} else if (
								e.element.type == 'bpmn:ExclusiveGateway'
							) {
								that.conditionStatus = true;
								that.nodeStatus = false;
							} else {
								that.nodeStatus = false;
								that.conditionStatus = false;
							}
							console.log('点击了element');
						}
					});
				});
			},
			elementChanged(eventType, e) {
				// var shape = this.getShape(e.element.id)
				// console.log(shape, 22222222)
				// if (!shape) {
				//     if (shape.type) {
				//         // 若是shape为null则表示删除, 无论是shape还是connect删除都调用此处
				//         console.log('无效的shape')
				//         // 由于上面已经用 shape.removed 检测了shape的删除, 因此这里只判断是否是线
				//         if (this.isSequenceFlow(shape.type)) {
				//             console.log('删除了线')
				//         }
				//     }
				// }
				// if (shape.type) {
				//     if (!this.isInvalid(shape.type)) {
				//         if (this.isSequenceFlow(shape.type)) {
				//             console.log('改变了线')
				//         }
				//     }
				// }
			},
			isSequenceFlow(type) {
				// 判断是否是线
				return type === 'bpmn:SequenceFlow';
			},
			getShape(id) {
				var elementRegistry = this.bpmnModeler.get('elementRegistry');
				return elementRegistry.get(id);
			},
			isInvalid(param) {
				// 判断是否是无效的值
				return param === null || param === undefined || param === '';
			},
		},
	};
</script>

<style lang="scss" scoped>
	.el-form-item--small .el-form-item__content {
		height: auto !important;
	}

	.rightMenu {
		margin-top: 20px;
		width: 300px;
		margin-right: 10px;
	}

	.container {
		display: flex;
	}

	.bpmn-canvas {
		width: 100%;
		height: 100vh;
		background: url('')
			repeat !important;
	}

	.action {
		position: fixed;
		bottom: 10px;
		left: 10px;
		display: flex;
	}

	.upload-demo {
		margin-right: 10px;
	}

	// 右菜单样式(注释隐藏菜单)
	// .bpmn-js-properties-panel {
	//   position: absolute;
	//   top: 0;
	//   right: 0px;
	//   width: 300px;
	//   max-height: 500px;
	//   overflow-y: auto;
	//   border: 1px solid rgba(0,0,0,0.1);
	// }
	.djs-palette.two-column.open {
		width: 50px;
	}

	.djs-palette {
		width: 55px;
	}
</style>
